using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;

namespace CriticalSystems.Instrumentation.Internal
{
    internal static class ReflectionHelper
    {
        private static readonly IList<string> infrastructureNamespaces = new List<string>();

        static ReflectionHelper()
        {
            infrastructureNamespaces.Add("CriticalSystems.Instrumentation");
            infrastructureNamespaces.Add("CriticalSystems.Instrumentation.Internal");
        }

        public static MethodBase GetCallingMethod()
        {
            return GetCallingMethod(false);
        }

        public static MethodBase GetCallingMethod(bool clientCaller)
        {
            const int INDEX_CALLING_METHOD = 2;        // This will always be at least 2 calls deep.
            StackTrace stack = new StackTrace();
            MethodBase method = null;
            bool outOfInfrastructure = false;

            //    Move up the stack trace, until we leave this class and enter the calling one.
            //    (If something weird happens and we don't leave this class just go to the top).
            for (int offSet = INDEX_CALLING_METHOD; offSet < stack.FrameCount; offSet++)
            {
                method = stack.GetFrame(offSet).GetMethod();
                if (outOfInfrastructure)
                {
                    break;
                }
                if (!infrastructureNamespaces.Contains(method.DeclaringType.Namespace))
                {
                    outOfInfrastructure = true;
                    if (!clientCaller)
                    {
                        break;
                    }
                }
            }

            //    Return the method that called into this class.
            return method;
        }
    }
}
